﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Xml;
using System.Windows.Controls;
using SHomeWorkshop.LunarConcept.ModifingManager;

namespace SHomeWorkshop.LunarConcept
{
    /// <summary>
    /// 创建时间：2011年12月27日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：此列表用以承载“撤销”与“重做”的各个“修改项（ModifingItem）”。
    ///           ——每个“修改项（即：修改，ModifingItem）”包含至少一个“动作（Action）”。
    /// 
    /// 用法：    主窗口应创建本类的唯一一个实例。
    ///           主窗口若提供“RegisterModifingItem()”方法，则只应该是对本类中同名方法的封装！！
    /// </summary>
    public class ModifingList<TAction, TInfo> : List<ModifingItem<TAction, TInfo>>
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// 构造一个“可撤销项”的列表。
        /// </summary>
        /// <param name="masterEditor">所属编辑器。</param>
        public ModifingList(IModifingManager<TAction, TInfo> parentEditor)
        {
            this.masterModifingManager = parentEditor;
        }

        #endregion

        #region 字段与属性===================================================================================================

        /// <summary>
        /// 能否重做。（取决于是否已经撤销到最晚一个“修改项”）。
        /// </summary>
        public bool CanRedo
        {
            get
            {
                if (Point < -1 || Point > this.Count - 2)//减2，是因为Redo运算时会先加1。最大索引值只能是Count-1。
                {
                    return false;
                }

                if (this.Count <= 0) return false;
                return true;
            }
        }

        /// <summary>
        /// 能否撤销。（取决于是否已经撤销到最早一个“修改项”）。
        /// </summary>
        public bool CanUndo
        {
            get
            {
                if (Point < 0 || Point > this.Count - 1) return false;
                if (this.Count <= 0) return false;
                return true;
            }
        }

        private IModifingManager<TAction, TInfo> masterModifingManager;
        /// <summary>
        /// 使用此“修改项列表（ModifingsList）”的编辑器。
        /// ——一般应是主窗口或总的封装编辑器（本程序中应是指EditorManager）！
        /// </summary>
        public IModifingManager<TAction, TInfo> MasterModifingManager
        {
            get { return masterModifingManager; }
        }

        //对于masterModifingManager来说，如果下一步进行的操作不是Redo，则应删除多余“可撤销项目”。
        private int point = -1;
        /// <summary>
        /// 表示当前Undo或Redo到哪一步，其实就是用作ModifingItemsList的索引。
        /// point的初始值为-1。
        /// </summary>
        public int Point
        {
            get { return point; }
        }

        private int pointOfSaving = -1;
        /// <summary>
        /// ★★★★★在保存文档、打开文档时，要注意同步这个值★★★★★
        /// 
        /// [只读]表示执行“保存”操作时的Point。如果撤销或重做后，与此值相等，则表示
        /// 当前应显示为“已保存”。
        /// </summary>
        public int PointOfSaving
        {
            get { return pointOfSaving; }
        }

        #endregion

        #region 方法=========================================================================================================

        /// <summary>
        /// 将某次修改所生成的相关信息以一个ModifingItem实例封装起来。然后，注册到“ModifingList”中。
        /// 
        /// ——以便于撤销与重做。
        /// 
        /// ★★★此方法并删除列表中在当前Point之后的所有项——这些项将不能再用于Redo()。
        /// </summary>
        public void RegisterModifingItem(ModifingItem<TAction, TInfo> modifingItem)
        {
            if (modifingItem == null) return;

            if (this.Contains(modifingItem))
            {
                MessageBox.Show("　　出现异常，撤销项被重复添加！",
                    Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            if (this.point > -1)
            {
                for (int i = this.Count - 1; i > point; i--)
                {
                    this.RemoveAt(i);
                }
            }
            else
            {
                this.Clear();
            }

            if (PointOfSaving > point)
            {
                pointOfSaving = -2;
            }

            this.Add(modifingItem);
            this.point++;

            if (MasterModifingManager != null)
            {
                masterModifingManager.IsModified = !(point == pointOfSaving);
            }

            OnModifingItemRegistered(this,
                new ModifingEventArgs<TAction, TInfo>(modifingItem));
        }


        /// <summary>
        /// 将Point后移一位，并以新位置（Point）记录的NewValue来引发RedoExecuted事件。
        /// </summary>
        public void Redo()
        {
            if (CanRedo == false) return;

            //注意：此处与Undo不同，得先加。
            point++;

            ModifingEventArgs<TAction, TInfo> e =
                new ModifingEventArgs<TAction, TInfo>
                    (this[point] as ModifingItem<TAction, TInfo>); ;

            //重做时，point++;不能放在此处，而是方法头部。

            if (point == pointOfSaving)
            {
                MasterModifingManager.IsModified = false;
            }
            else
            {
                MasterModifingManager.IsModified = true;
            }

            OnRedoExecuted(this, e);
        }

        /// <summary>
        /// 重置修改状态。
        /// </summary>
        public void Reset()
        {
            if (MasterModifingManager != null) MasterModifingManager.IsModified = false;

            pointOfSaving = point = -1;

            this.Clear();
        }

        /// <summary>
        /// 同步PointOfSaving。
        /// </summary>
        public void SynchronizeSavePoint()
        {
            pointOfSaving = point;
        }

        /// <summary>
        /// 将Point前移一位，并以新位置（Point）记录的NewValue来引发RedoExecuted事件。
        /// </summary>
        public void Undo()
        {
            if (CanUndo == false) return;

            ModifingEventArgs<TAction, TInfo> e =
                new ModifingEventArgs<TAction, TInfo>
                    (this[point] as ModifingItem<TAction, TInfo>);

            point--;

            if (point == pointOfSaving)
            {
                MasterModifingManager.IsModified = false;
            }
            else
            {
                MasterModifingManager.IsModified = true;
            }

            OnUodoExecuted(this, e);
        }

        #endregion

        #region 事件=========================================================================================================

        /// <summary>
        /// [事件]表示“撤销与重做列表”接到了“重做命令”。
        /// </summary>
        public event EventHandler<ModifingEventArgs<TAction, TInfo>> RedoExecuted;

        protected void OnRedoExecuted(object sender, ModifingEventArgs<TAction, TInfo> e)
        {
            if (RedoExecuted != null)
            {
                RedoExecuted(sender, e);
            }
        }

        /// <summary>
        /// [事件]表示向“撤销与重做列表”中注册了一个“修改项”。
        /// </summary>
        public event EventHandler<ModifingEventArgs<TAction, TInfo>> ModifingItemRegistered;

        protected void OnModifingItemRegistered(object sender, ModifingEventArgs<TAction, TInfo> e)
        {
            if (ModifingItemRegistered != null)
            {
                ModifingItemRegistered(sender, e);
            }
        }

        /// <summary>
        /// [事件]表示“撤销与重做列表”接到了“撤销命令”。
        /// 在使用此事件时，应注意foreach处理Actions时要逆序！！！
        /// </summary>
        public event EventHandler<ModifingEventArgs<TAction, TInfo>> UndoExecuted;

        protected void OnUodoExecuted(object sender, ModifingEventArgs<TAction, TInfo> e)
        {
            if (UndoExecuted != null)
            {
                UndoExecuted(sender, e);
            }
        }

        #endregion
    }
}
